//
//  ArcDatePicker.swift
//  ZBDatePicker
//
//  Created by BO ZHOU on 2021/2/4.
//

import UIKit

@objcMembers class ArcDatePicker: UIView {

    @objc enum Mode: Int {
        case ym         // 年月
        case ymd        // 年月日
    }

    var showMode: Mode = .ymd {
        didSet {
            if oldValue != showMode {
                
                self.pickerView.reloadAllComponents()
            }
        }
    }
    
    
    /** 最小时间限制, 默认1970.1.1 */
    var minDate: Date {
        set {
            _minDate = fixMinDate(minDate: newValue)
        }
        get {
            return _minDate
        }
    }
    
    var _minDate: Date = "1970-01-01".toDate(format: "yyyy-MM-dd") {
        didSet {
            dateManager.minDate = minDate
        }
    }
    
    /** 最大时间限制, 默认为当前时间 */
    var maxDate: Date! = Date() {
        didSet {
            dateManager.maxDate = maxDate
        }
    }
    
    /** 选中日期回调 */
    var didSelectDateBlock: ((_ date: Date) -> Void)? = nil {
        didSet {
            // 初始化设置的时候, 回调一次当前滚动到的日期
            self.didSelectDateBlock?(selectedDate)
        }
    }
    
    /** 根据年份返回月份, 根据年份月份返回日的单例 */
    private let dateManager: ArcDataManager = {
        let manager = ArcDataManager.shared
        manager.maxDate = Date()
        return manager
    }()
    
    /** 时间选择器view */
    private lazy var pickerView: UIPickerView = {
        
        let pickerview = UIPickerView()
        pickerview.delegate = self
        pickerview.dataSource = self
        return pickerview
    }()
    
    /** 当前选中的年月日 */
    private var currentSelectYMD: (currentSelectYear: Int, currentSelectMonth: Int, currentSelectDay: Int)! {
        didSet {
            didSelectDateBlock?(selectedDate)
        }
    }
    
    /** 当前选中的年 */
    private var currentSelectYear: Int = 0
    
    /** 当前选中的月 */
    private var currentSelectMonth: Int = 0
    
    /** 当前选中的日 */
    private var currentSelectDay: Int = 0
    
    /**
     * 初始化
     * - parameter minDate: 最小时间, 不设置默认为1970.1.1
     * - parameter maxDate: 最大时间, 不设置默认为当前时间
     * - parameter scrollDate: 初始化之后默认选中的时间, 不设置默认为当前时间
     */
    init(frame: CGRect, minDate: Date? = nil, maxDate: Date? = nil, scrollDate: Date? = nil) {
        
        if maxDate != nil {
            self.maxDate = maxDate!
            self.dateManager.maxDate = maxDate!
        }
        
        super.init(frame: frame)
        
        if minDate != nil {
            
            self.minDate = minDate!
            self.dateManager.minDate = minDate!
        }
        dowithInit()
        
        let actualScrollDate = scrollDate ?? self.maxDate ?? Date()
        scrollTo(date: actualScrollDate)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        dowithInit()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.pickerView.frame = self.bounds
    }
    
    private func dowithInit() {
        addSubview(pickerView)
        pickerView.frame = self.bounds
        self.backgroundColor = .white
        self.pickerView.backgroundColor = .clear
    }
 
    /**
     * 滚动到设置的日期
     */
    func scrollTo(date: Date) {
        
        // 当时间滚动到最小时间时, 设置的mindate和选中的最小时间 比如minDate为2020.01.01 06:00, date为2020.01.01.05:00, 会导致date < mindate (正常应该是date >= mindate)
        if date < minDate || date > maxDate {
            return
        }
        
        self.currentSelectYear = date.year
        self.currentSelectMonth = date.month
        self.currentSelectDay = date.day
        refreshYMDAndCallBack()
        
        if showMode == .ym {
            if let yearIndex = dateManager.currentYears.firstIndex(of: currentSelectYear) {
                pickerView.selectRow(yearIndex, inComponent: 0, animated: true)
                pickerView.reloadComponent(1)
            }
            if let monthIndex = dateManager.getMonthArr(withYear: currentSelectYear).firstIndex(of: currentSelectMonth) {
                pickerView.selectRow(monthIndex, inComponent: 1, animated: true)
            }
        } else if showMode == .ymd {
            if let yearIndex = dateManager.currentYears.firstIndex(of: currentSelectYear) {
                pickerView.selectRow(yearIndex, inComponent: 0, animated: true)
                pickerView.reloadComponent(1)
            }
            if let monthIndex = dateManager.getMonthArr(withYear: currentSelectYear).firstIndex(of: currentSelectMonth) {
                pickerView.selectRow(monthIndex, inComponent: 1, animated: true)
                pickerView.reloadComponent(2)
            }
            if let dayIndex = dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth).firstIndex(of: currentSelectDay) {
                pickerView.selectRow(dayIndex, inComponent: 2, animated: true)
            }
        }
        
        didSelectDateBlock?(date)
    }
    
    
    /**
     * 提供外界手动调用选中日期的方法, 选中当前日期并返回
     */
    @discardableResult func refreshSelectDate(_ date: Date?) -> Date {
        
        let showDate = date ?? selectedDate
        self.didSelectDateBlock?(showDate)
        return showDate
    }
    
    /**
     * 提供外界手动调用选中日期的方法, 选中当前日期并滚动到当前日期
     */
    @discardableResult func refreshSelectDateAndScroll(_ date: Date?) -> Date {
        
        let showDate = date ?? selectedDate
        self.scrollTo(date: showDate)
        self.didSelectDateBlock?(showDate)
        return showDate
    }
    
    /**
     * 当年/月/日修改的时候, 需要call回调
     */
    private func refreshYMDAndCallBack() {
        self.currentSelectYMD = (currentSelectYear, currentSelectMonth, currentSelectDay)
    }
    
    /**
     * 根据当前选中的日期生成Date对象, 如果没有选中过, 返回当前日期
     */
    private var selectedDate: Date {
        
        if self.showMode == .ym {
            return Date.date(fromYear: currentSelectYear, month: currentSelectMonth)
        } else if self.showMode == .ymd {
            return Date.date(fromYear: currentSelectYear, month: currentSelectMonth, day: currentSelectDay)
        } else {
            return Date()
        }
    }
    
    /**
     * 根据showMode重置minDate, 防止误差几小时导致时间判断错误
     */
    private func fixMinDate(minDate: Date) -> Date {

        let minDateString = minDate.toString(format: "yyyy-MM-dd")
        return minDateString.toDate(format: "yyyy-MM-dd")
    }

}


extension ArcDatePicker: UIPickerViewDelegate, UIPickerViewDataSource {
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        if showMode == .ym {
            return 2
        } else if showMode == .ymd {
            return 3
        } else {
            return 0
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if showMode == .ym {
            
            if component == 0 {
                return dateManager.currentYears.count
            } else {
                return dateManager.getMonthArr(withYear: self.currentSelectYear).count
            }
        } else if showMode == .ymd {
            
            if component == 0 {
                return dateManager.currentYears.count
            } else if component == 1 {
                return dateManager.getMonthArr(withYear: self.currentSelectYear).count
            } else {
                return dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth).count
            }
        } else {
            return 0
        }
    }
    
    /**
     * 该方法只有手动ui交互才会调用, 代码scroll不会调用
     */
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        
        if showMode == .ym {
            
            if component == 0 {
                currentSelectYear = dateManager.currentYears[row]
                
                // warning: 比如限制了最大日期为2021.2.10, 当滑动到2019.12.1时, 选中年份为2019, 选中月份为12, 选中日期为1
                //          然后滚动年份至2021, 因为最大日期只能显示2021.2月, 所以component为1的列自动显示为2, 但是currentSelectMonth还是为12,
                //          然后去取对应日期的时候, 是按照2021.12月来获取日期, 获取了空数组. 产生了问题
                
                // 当前选中年份 = 最大或最小限制年份时, 要处理可能出现的上述warning问题
                
                // fix相关bug: 上述逻辑修改为, 切换年份的时候, 月份自动按照reloadComponent之后的pickerview自动选中的rowIndex获取
                // reloadComponent是一个同步方法, 但是他只会同步调用numberOfRowsInComponent, 不会调用viewForRow forComopnent方法(异步)
                // 似乎取消dispatch也行, 后面测试一下
                pickerView.reloadComponent(1)
                DispatchQueue.main.async { [unowned self] in
                    
                    let row = pickerView.selectedRow(inComponent: 1)
                    let actualRow = min(row, dateManager.getMonthArr(withYear: currentSelectYear).count - 1)
                    currentSelectMonth = dateManager.getMonthArr(withYear: currentSelectYear)[actualRow]
                    refreshYMDAndCallBack()
                }
            } else if component == 1 {
                DispatchQueue.main.async { [unowned self] in
                    
                    let actualRow = min(row, dateManager.getMonthArr(withYear: currentSelectYear).count - 1)
                    self.currentSelectMonth = dateManager.getMonthArr(withYear: currentSelectYear)[actualRow]
                    refreshYMDAndCallBack()
                }
            }
        } else if showMode == .ymd {
            if component == 0 {
                currentSelectYear = dateManager.currentYears[row]
                
                pickerView.reloadComponent(1)
                
                // 异步执行, 确保在reloadComponent完成之后执行
                DispatchQueue.main.async { [unowned self] in
                    
                    let row = pickerView.selectedRow(inComponent: 1)
                    let actualRow = min(row, dateManager.getMonthArr(withYear: currentSelectYear).count - 1)
                    currentSelectMonth = dateManager.getMonthArr(withYear: currentSelectYear)[actualRow]
                    pickerView.reloadComponent(2)
                    
                    DispatchQueue.main.async {
                        
                        let row = pickerView.selectedRow(inComponent: 2)
                        let actualRow = min(row, dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth).count - 1)
                        currentSelectDay = dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth)[actualRow]
                        refreshYMDAndCallBack()
                    }
                }

            } else if component == 1 {

                let actualRow = min(row, dateManager.getMonthArr(withYear: currentSelectYear).count - 1)
                currentSelectMonth = dateManager.getMonthArr(withYear: currentSelectYear)[actualRow]
                
                pickerView.reloadComponent(2)
                
                DispatchQueue.main.async { [unowned self] in
                    
                    // 防止用户手贱,滚动过程中还是要手动点击越界的内容
                    let row = pickerView.selectedRow(inComponent: 2)
                    let actualRow = min(row, dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth).count - 1)
                    currentSelectDay = dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth)[actualRow]

                    refreshYMDAndCallBack()
                }

            } else if component == 2 {
                
                DispatchQueue.main.async { [unowned self] in
                    
                    // 防止用户手贱, 双向滚动之后还要手动点击没来及刷新的越界的内容导致闪退
                    let actualRow = min(row, dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth).count - 1)
                    
                    if actualRow != row {
                        print("该手贱的用户数据被修复.....")
                    }
                    currentSelectDay = dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth)[actualRow]

                    refreshYMDAndCallBack()
                }
            }
        } else {
            refreshYMDAndCallBack()
        }
    }

    
    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        
        //设置分割线的颜色
        for view in pickerView.subviews {
            if view.frame.height < 1 {
                view.backgroundColor = UIColor.init(hexString: "#eeeeee")
            }
        }
        
        let string = getStringContent(withComponent: component, row: row)
        let label = UILabel()
        label.textColor = UIColor.init(hexString: "#333333")
        label.font = UIFont.systemFont(ofSize: 14)
        label.text = string
        label.textAlignment = .center
        
        return label
    }
    
    
    /**
     * 根据component和row获取对应的string
     */
    private func getStringContent(withComponent component: Int, row: Int) -> String {
        
        var rowString = ""
        if showMode == .ym {
            if component == 0 {
                rowString = dateManager.currentYears[row].toString + "年"
            } else if component == 1 {
                rowString = dateManager.getMonthArr(withYear: self.currentSelectYear)[row].toString + "月"
            }
        } else if showMode == .ymd {
            if component == 0 {
                rowString = dateManager.currentYears[row].toString + "年"
            } else if component == 1 {
                rowString = dateManager.getMonthArr(withYear: self.currentSelectYear)[row].toString + "月"
            } else {
                rowString = dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth)[row].toString + "日"
            }
        }
        return rowString
    }
    
//    private func fixMonthAndDay() {
//
//        // 当选中的月份index和上一次选中月份一致时, 月份不会滚动
//        // 当上一次选中月份的index, 不在当前年份对应的月份index中时, 如果上一次大, 就切换到当前对应月份的最大index, 如果小, 对应最小index
//        if currentSelectYear == self.minDate.year {
//
//            // 如果选中年份为最小限制年份, 当最小限制月份 比 currentSelectMonth还大时, 将currentSelectMonth设置为最小限制月份
//            let minMonth = minDate.month
//            currentSelectMonth = max(currentSelectMonth, minMonth)
//
//            if currentSelectMonth == minMonth {
//                currentSelectDay = max(currentSelectDay, minDate.day)
//            }
//
//        } else if currentSelectYear == self.maxDate.year {
//
//            let maxMonth = maxDate.month
//            currentSelectMonth = min(currentSelectMonth, maxMonth)
//
//            if currentSelectMonth == maxMonth {
//                currentSelectDay = min(currentSelectDay, maxDate.day)
//            }
//
//        } else {
//
//            // 就算不是最大限制日期和最小限制日期, 也需要判断修改day, 比如从12.31 滑动了月份到11月, 要显示30号 而不是31
//            let maxDay = dateManager.getDayArr(withYear: currentSelectYear, month: currentSelectMonth).last!
//            if currentSelectDay > maxDay {
//                currentSelectDay = maxDay
//            }
//        }
//    }
//
//    private func fixMonth() {
//        if currentSelectYear == self.minDate.year {
//
//            // 如果选中年份为最小限制年份, 当最小限制月份 比 currentSelectMonth还大时, 将currentSelectMonth设置为最小限制月份
//            let minMonth = minDate.month
//            currentSelectMonth = max(currentSelectMonth, minMonth)
//
//        } else if currentSelectYear == self.maxDate.year {
//
//            let maxMonth = maxDate.month
//            currentSelectMonth = min(currentSelectMonth, maxMonth)
//        }
//    }
}
